/******************************************************************************
 *                  Shanghai ChipON Micro-Electronic Co.,Ltd
 ******************************************************************************
 *  @File Name        : kf8a100fxx_uart.c
 *  @Author           : ChipON AE/FAE Group
 *  @Date             : 2023-12-19
 *  @HW Version       : KF8A100Fxx
 *  @Lib Version      : V2.0.1
 *  @Description      : This file provides the driver for the uart module
 ******************************************************************************
 *  Copyright (C) by Shanghai ChipON Micro-Electronic Co.,Ltd
 *  All rights reserved.
 *
 *  This software is copyright protected and proprietary to
 *  Shanghai ChipON Micro-Electronic Co.,Ltd.
 *****************************************************************************/
/******************************************************************************
 *  |Date        |Version  |Author       |Description
 ******************************************************************************
 *  |2023-12-25  |V2.0     |Wang Junxiong|New creat
 *****************************************************************************/

/******************************************************************************
 **                     QAC Warnings
 *****************************************************************************/
/* PRQA S 0436 EOF #8-bit MCU Features: Direct Write Registers. */
/* PRQA S 1291, 1820, 1821, 1822, 1823, 1851, 1853, 3715, 3757, 3760 EOF #Registers are essentially unsigned numbers. */
/* PRQA S 2754 EOF #Level 7 problem due to unsupported assembly instructions. */
/* PRQA S 3768, 3771, 4130, 4393, 4434, 4443, 4446, 4461, 4532 EOF #Registers are essentially unsigned numbers. */

/******************************************************************************
 *                      Include Files
 *****************************************************************************/
#include "kf8a100fxx_uart.h"
/******************************************************************************
 *                      Macro Definitions
 *****************************************************************************/

/******************************************************************************
 *                      Constants
 *****************************************************************************/

/******************************************************************************
 *                      Type definitions
 *****************************************************************************/

/******************************************************************************
 *                      Variables
 *****************************************************************************/

/******************************************************************************
 *                      Function definitions
 *****************************************************************************/

/**
 * @brief UART initialize
 *
 * @param Prescaler = the baud rate is 16000000/[16*(prescaler+1)]
 * @param Mode 0: 8bit Mode; 1: 9bit Mode
 */
void Uart1_Init(Uart_BaudRateModeType Prescaler, Uart_BitModeType Mode)
{
    uint8_t Source = SCF1, RegTemp = SCF0;
    /* Enable serial module, enable receiver */
    RSCTL1 = 0x90u;
    /* Receiver idle */
    BRCTL1  = 0x50u;
    BR1CKS1 = Source;
    Source ^= RegTemp;
    BR1CKS0 = Source;
    /* Enable transmit function, shift register empty */
    TSCTL1 = 0x22u;
    /* The baud rate is 16000000/[16*(prescaler+1)] */
    EUBRGL1 = (uint8_t)Prescaler;
    EUBRGH1 = (uint8_t)((uint16_t)Prescaler >> 8u);
    if (Mode == UART_9BIT_MODE)
    {
        /* Enable 9-bit receive */
        T1X9 = 1u;
        R1X9 = 1u;
    }
    else
    {
        /* nothing */
    }
}

/**
 * @brief UART initialize
 *
 * @param Prescaler = the baud rate is 16000000/[16*(prescaler+1)]
 * @param Mode 0: 8bit Mode; 1: 9bit Mode
 */
void Uart2_Init(Uart_BaudRateModeType Prescaler, Uart_BitModeType Mode)
{
    uint8_t Source = SCF1, RegTemp = SCF0;
    /* Enable serial module, enable receiver */
    RSCTL2 = 0x90u;
    /* Receiver idle */
    BRCTL2  = 0x50u;
    BR2CKS1 = Source;
    Source ^= RegTemp;
    BR2CKS0 = Source;
    /* Enable transmit function, shift register empty */
    TSCTL2 = 0x22u;
    /* The baud rate is 16000000/[16*(prescaler+1)] */
    EUBRGL2 = (uint8_t)Prescaler;
    EUBRGH2 = (uint8_t)((uint16_t)Prescaler >> 8u);
    if (Mode == UART_9BIT_MODE)
    {
        /* Enable 9-bit receive */
        T2X9 = 1u;
        R2X9 = 1u;
    }
    else
    {
        /* nothing */
    }
}

/**
 * @brief Even checksum function, software checksum.
 *
 * @param Data data
 * @return uint8_t If the number of 1 is odd, then return 1, if the number of 1 is even, then return 0
 */
/* PRQA S 3408 1 #Internal variables, functions are not modified. */
uint8_t Parity_Check_even(uint8_t Data)
{
    uint8_t val = 0u, x = Data;
    while (x > 0u)
    {
        /* val and x are different-or operations */
        val ^= x;
        /* x shifted one place to the right */
        x >>= 1u;
    }
    /* Take the last bit of the operation. The last bit of the binary form of val returns 1 if the bit is 1 and 0 if the
     * bit is 0 */
    return (val & 0x1u);
}

/**
 * @brief Odd calibration function, software calibration.
 *
 * @param Data data
 * @return uint8_t Returns 0 if the number of 1's is odd, or 1 if the number of 1's is even.
 */
/* PRQA S 3408 1 #Internal variables, functions are not modified. */
uint8_t Parity_Check_odd(uint8_t Data)
{
    uint8_t val = 0u, x = Data;
    while (x > 0u)
    {
        /* val and x are different-or operations */
        val ^= x;
        /* x shifted one place to the right */
        x >>= 1u;
    }
    /* Take the last bit of the operation. The last bit of the binary form of val returns 0 if the bit is 1 and 1 if the
     * bit is 0 */
    if ((val & 0x1u) > 0u)
    {
        x = 0u;
    }
    else
    {
        x = 1u;
    }
    return x;
}

/**
 * @brief Receive a byte, and the 9th bit parity correct return data, data in the buffer, error return 0.
 *
 * @param Mode 0 - none parity mode, 1 - odd parity mode, 2 - even parity mode
 * @return uint8_t data, error returns 0
 */
uint8_t Uart1_Rec_Byte(Uart_ParityModeType Mode)
{
    uint8_t temp, d9, check = 0u;

    d9   = RX9D1;
    temp = RXSDR1;
    if (Mode == UART_ODD_MODE)
    {
        check = Parity_Check_odd(temp);
    }
    else if (Mode == UART_EVEN_MODE)
    {
        check = Parity_Check_even(temp);
    }
    else
    {
        check = d9;
    }

    if (check == d9)
    {
        /* nothing */
    }
    else
    {
        temp = 0u;
    }
    return temp;
}

/**
 * @brief Receive a byte, and the 9th bit parity correct return data, data in the buffer, error return 0.
 *
 * @param Mode 0 - none parity mode, 1 - odd parity mode, 2 - even parity mode
 * @return uint8_t data, error returns 0
 */
uint8_t Uart2_Rec_Byte(Uart_ParityModeType Mode)
{
    uint8_t temp, d9, check = 0u;

    d9   = RX9D2;
    temp = RXSDR2;
    if (Mode == UART_ODD_MODE)
    {
        check = Parity_Check_odd(temp);
    }
    else if (Mode == UART_EVEN_MODE)
    {
        check = Parity_Check_even(temp);
    }
    else
    {
        check = d9;
    }

    if (check == d9)
    {
        /* nothing */
    }
    else
    {
        temp = 0u;
    }
    return temp;
}

/**
 * @brief Even checksum function, software checksum. Parity call for non-interruptible functions
 *
 * @param Data data
 * @return uint8_t Returns 1 if the number of 1's is odd, or 0 if the number of 1's is even.
 */
/* PRQA S 3408 1 #Internal variables, functions are not modified. */
uint8_t Parity_Check_even_1(uint8_t Data)
{
    uint8_t val = 0u, x = Data;
    while (x > 0u)
    {
        /* val and x are different-or operations */
        val ^= x;
        /* x shifted one place to the right */
        x >>= 1u;
    }
    /* Take the last bit of the operation. The last bit of the binary form of val returns 1 if the bit is 1 and 0 if the
     * bit is 0 */
    return (val & 0x1u);
}

/**
 * @brief Odd calibration function, software calibration. Parity call for non-interruptible functions
 *
 * @param Data data
 * @return uint8_t Returns 0 if the number of 1's is odd, or 1 if the number of 1's is even.
 */
/* PRQA S 3408 1 #Internal variables, functions are not modified. */
uint8_t Parity_Check_odd_1(uint8_t Data)
{
    uint8_t val = 0u, x = Data;
    while (x > 0u)
    {
        /* val and x are different-or operations */
        val ^= x;
        /* x shifted one place to the right */
        x >>= 1u;
    }
    /* Take the last bit of the operation. The last bit of the binary form of val returns 0 if the bit is 1 and 1 if the
     * bit is 0 */
    if ((val & 0x1u) > 0u)
    {
        x = 0u;
    }
    else
    {
        x = 1u;
    }
    return x;
}

/**
 * @brief UART1 Send one byte with parity
 *
 * @param SendData Single byte to be sent
 * @param Mode 0 - none parity mode, 1 - odd parity mode, 2 - even parity mode
 * @return Uart_StatusType
 * 0: UART_OK,
 * 1: UART_TIMEOUT,
 */
Uart_StatusType Uart1_PutChar(uint8_t SendData, Uart_ParityModeType Mode)
{
    uint16_t        timeout = UART_TIMEOUT_CONFIG;
    Uart_StatusType state   = UART_OK;

    if (Mode == UART_ODD_MODE)
    {
        TX9D1 = Parity_Check_odd_1(SendData);
    }
    else if (Mode == UART_EVEN_MODE)
    {
        TX9D1 = Parity_Check_even_1(SendData);
    }
    else
    {
        /* nothing */
    }
    /* Return to original value */
    TXSDR1 = SendData;
    while ((TX1IF == 0u) && (timeout > 0u))
    {
        timeout = timeout - 1u;
    }
    if (timeout == 0u)
    {
        state = UART_TIMEOUT;
    }
    else
    {
        /* nothing */
    }
    return state;
}

/**
 * @brief UART2 Send one byte with parity
 *
 * @param SendData Single byte to be sent
 * @param Mode 0 - none parity mode, 1 - odd parity mode, 2 - even parity mode
 * @return Uart_StatusType
 * 0: UART_OK,
 * 1: UART_TIMEOUT,
 */
Uart_StatusType Uart2_PutChar(uint8_t SendData, Uart_ParityModeType Mode)
{
    uint16_t        timeout = UART_TIMEOUT_CONFIG;
    Uart_StatusType state   = UART_OK;

    if (Mode == UART_ODD_MODE)
    {
        TX9D2 = Parity_Check_odd_1(SendData);
    }
    else if (Mode == UART_EVEN_MODE)
    {
        TX9D2 = Parity_Check_even_1(SendData);
    }
    else
    {
        /* nothing */
    }
    /* Return to original value */
    TXSDR2 = SendData;
    while ((TX2IF == 0u) && (timeout > 0u))
    {
        timeout = timeout - 1u;
    }
    if (timeout == 0u)
    {
        state = UART_TIMEOUT;
    }
    else
    {
        /* nothing */
    }
    return state;
}

/**
 * @brief UART1 Multi-Byte Transmission
 *
 * @attention This function cannot be called within an interrupt service routine.
 *
 * @param Buf data address
 * @param Len data length
 * @param Mode 0 - none parity mode, 1 - odd parity mode, 2 - even parity mode
 * @return Uart_StatusType
 * 0: UART_OK,
 * 1: UART_TIMEOUT,
 */
Uart_StatusType Uart1_Send(const uint8_t *Buf, uint8_t Len, Uart_ParityModeType Mode)
{
    uint16_t        timeout;
    Uart_StatusType state   = UART_OK;
    const uint8_t  *buf_ptr = Buf;
    uint8_t         i       = 0u, temp;
    for (i = 0u; i < Len; i++)
    {
        temp = *buf_ptr;
        buf_ptr++;
        if (Mode == UART_ODD_MODE)
        {
            TX9D1 = Parity_Check_odd_1(temp);
        }
        else if (Mode == UART_EVEN_MODE)
        {
            TX9D1 = Parity_Check_even_1(temp);
        }
        else
        {
            /* nothing */
        }
        TXSDR1 = temp;

        timeout = UART_TIMEOUT_CONFIG;
        while ((TX1IF == 0u) && (timeout > 0u))
        {
            timeout = timeout - 1u;
        }
        if (timeout == 0u)
        {
            state = UART_TIMEOUT;
            break;
        }
        else
        {
            /* nothing */
        }
    }
    return state;
}

/**
 * @brief UART2 Multi-Byte Transmission
 *
 * @attention This function cannot be called within an interrupt service routine.
 *
 * @param Buf data address
 * @param Len data length
 * @param Mode 0 - none parity mode, 1 - odd parity mode, 2 - even parity mode
 * @return Uart_StatusType
 * 0: UART_OK,
 * 1: UART_TIMEOUT,
 */
Uart_StatusType Uart2_Send(const uint8_t *Buf, uint8_t Len, Uart_ParityModeType Mode)
{
    uint16_t        timeout;
    Uart_StatusType state   = UART_OK;
    const uint8_t  *buf_ptr = Buf;
    uint8_t         i       = 0u, temp;
    for (i = 0u; i < Len; i++)
    {
        temp = *buf_ptr;
        buf_ptr++;
        if (Mode == UART_ODD_MODE)
        {
            TX9D2 = Parity_Check_odd_1(temp);
        }
        else if (Mode == UART_EVEN_MODE)
        {
            TX9D2 = Parity_Check_even_1(temp);
        }
        else
        {
            /* nothing */
        }
        TXSDR2 = temp;

        timeout = UART_TIMEOUT_CONFIG;
        while ((TX2IF == 0u) && (timeout > 0u))
        {
            timeout = timeout - 1u;
        }
        if (timeout == 0u)
        {
            state = UART_TIMEOUT;
            break;
        }
        else
        {
            /* nothing */
        }
    }
    return state;
}

/**
 * @brief UART1 String Transmission
 *
 * @attention This function cannot be called within an interrupt service routine.
 *
 * @param Buf data address
 * @param Mode 0 - none parity mode, 1 - odd parity mode, 2 - even parity mode
 * @return Uart_StatusType
 * 0: UART_OK,
 * 1: UART_TIMEOUT,
 */
Uart_StatusType Uart1_SendString(const uint8_t *Buf, Uart_ParityModeType Mode)
{
    uint16_t        timeout;
    Uart_StatusType state   = UART_OK;
    const uint8_t  *buf_ptr = Buf;
    uint8_t         temp;
    do
    {
        /* Return to original value */
        temp = *buf_ptr;
        if (Mode == UART_ODD_MODE)
        {
            TX9D1 = Parity_Check_odd_1(temp);
        }
        else if (Mode == UART_EVEN_MODE)
        {
            TX9D1 = Parity_Check_even_1(temp);
        }
        else
        {
            /* nothing */
        }
        TXSDR1 = temp;

        timeout = UART_TIMEOUT_CONFIG;
        while ((TX1IF == 0u) && (timeout > 0u))
        {
            timeout = timeout - 1u;
        }
        if (timeout == 0u)
        {
            state = UART_TIMEOUT;
            break;
        }
        else
        {
            /* nothing */
        }
        /* PRQA S 3440 1 # It is more efficient to add one to a judgment this way. */
    } while (*buf_ptr++ != 0u);
    return state;
}

/**
 * @brief UART2 String Transmission
 *
 * @attention This function cannot be called within an interrupt service routine.
 *
 * @param Buf data address
 * @param Mode 0 - none parity mode, 1 - odd parity mode, 2 - even parity mode
 * @return Uart_StatusType
 * 0: UART_OK,
 * 1: UART_TIMEOUT,
 */
Uart_StatusType Uart2_SendString(const uint8_t *Buf, Uart_ParityModeType Mode)
{
    uint16_t        timeout;
    Uart_StatusType state   = UART_OK;
    const uint8_t  *buf_ptr = Buf;
    uint8_t         temp;
    do
    {
        /* Return to original value */
        temp = *buf_ptr;
        if (Mode == UART_ODD_MODE)
        {
            TX9D2 = Parity_Check_odd_1(temp);
        }
        else if (Mode == UART_EVEN_MODE)
        {
            TX9D2 = Parity_Check_even_1(temp);
        }
        else
        {
            /* nothing */
        }
        TXSDR2 = temp;

        timeout = UART_TIMEOUT_CONFIG;
        while ((TX2IF == 0u) && (timeout > 0u))
        {
            timeout = timeout - 1u;
        }
        if (timeout == 0u)
        {
            state = UART_TIMEOUT;
            break;
        }
        else
        {
            /* nothing */
        }
        /* PRQA S 3440 1 # It is more efficient to add one to a judgment this way. */
    } while (*buf_ptr++ != 0u);
    return state;
}

/**
 * @brief Auto Baud Rate Enable
 *
 */
void Uart1_Auto_BaudRate_Detection_Enable(void)
{
    ABRDEN1 = 1u;
    WUEN1   = 1u;
}

/**
 * @brief Auto Baud Rate Enable
 *
 */
void Uart2_Auto_BaudRate_Detection_Enable(void)
{
    ABRDEN2 = 1u;
    WUEN2   = 1u;
}

/**
 * @brief EUBRGL register decremented by one at the end of auto baud rate
 *
 */
void Uart1_Auto_BaudRate_EUBRGL_Sub1(void)
{
    EUBRGL1 -= 1u;
}

/**
 * @brief EUBRGL register decremented by one at the end of auto baud rate
 *
 */
void Uart2_Auto_BaudRate_EUBRGL_Sub1(void)
{
    EUBRGL2 -= 1u;
}

/**
 * @brief Converts 8bit data to 0 1 string and sends it out
 *
 * @param Data 8bit data
 * @param Mode 0 - none parity mode, 1 - odd parity mode, 2 - even parity mode
 */
void Uart1_Send8Bit2Char(uint8_t Data, Uart_ParityModeType Mode)
{
    uint8_t temp, data_temp = Data;
    uint8_t i;
    for (i = 0u; i < 8u; i++)
    {
        temp = data_temp & 0x80u;
        if (temp > 0u)
        {
            (void)Uart1_PutChar(49u, Mode);
        }
        else
        {
            (void)Uart1_PutChar(48u, Mode);
        }
        data_temp <<= 1u;
    }
}

/**
 * @brief Converts 8bit data to 0 1 string and sends it out
 *
 * @param Data 8bit data
 * @param Mode 0 - none parity mode, 1 - odd parity mode, 2 - even parity mode
 */
void Uart2_Send8Bit2Char(uint8_t Data, Uart_ParityModeType Mode)
{
    uint8_t temp, data_temp = Data;
    uint8_t i;
    for (i = 0u; i < 8u; i++)
    {
        temp = data_temp & 0x80u;
        if (temp > 0u)
        {
            (void)Uart2_PutChar(49u, Mode);
        }
        else
        {
            (void)Uart2_PutChar(48u, Mode);
        }
        data_temp <<= 1u;
    }
}

/**
 * @brief Converts 16bit data to 0 1 string and sends it out
 *
 * @param Data 16bit data
 * @param Mode 0 - none parity mode, 1 - odd parity mode, 2 - even parity mode
 */
void Uart1_Send16Bit2Char(uint16_t Data, Uart_ParityModeType Mode)
{
    uint16_t temp, data_temp = Data;
    uint8_t  i;
    for (i = 0u; i < 16u; i++)
    {
        temp = data_temp & 0x8000u;
        if (temp > 0u)
        {
            (void)Uart1_PutChar(49u, Mode);
        }
        else
        {
            (void)Uart1_PutChar(48u, Mode);
        }
        data_temp <<= 1u;
    }
}

/**
 * @brief Converts 16bit data to 0 1 string and sends it out
 *
 * @param Data 16bit data
 * @param Mode 0 - none parity mode, 1 - odd parity mode, 2 - even parity mode
 */
void Uart2_Send16Bit2Char(uint16_t Data, Uart_ParityModeType Mode)
{
    uint16_t temp, data_temp = Data;
    uint8_t  i;
    for (i = 0u; i < 16u; i++)
    {
        temp = data_temp & 0x8000u;
        if (temp > 0u)
        {
            (void)Uart2_PutChar(49u, Mode);
        }
        else
        {
            (void)Uart2_PutChar(48u, Mode);
        }
        data_temp <<= 1u;
    }
}

/**
 * @brief Uart1 deinitialization
 *
 */
void Uart1_DeInit(void)
{
    RSCTL1  = 0u;
    BRCTL1  = 0u;
    TSCTL1  = 0x02u;
    EUBRGL1 = 0u;
    EUBRGH1 = 0u;

    UPINSET1 = 0u;
    SLPEN1   = 0u;
    UARTMTH1 = 0u;
}

/**
 * @brief Uart2 deinitialization
 *
 */
void Uart2_DeInit(void)
{
    RSCTL2  = 0u;
    BRCTL2  = 0u;
    TSCTL2  = 0x02u;
    EUBRGL2 = 0u;
    EUBRGH2 = 0u;

    UPINSET2    = 0u;
    SLPEN2      = 0u;
    U7816TXCTL2 = 0x10u;
    U7816RXCTL2 = 0u;
    U7816CTL2   = 0u;
    CLKDIV2     = 0u;
    EGTCTL2     = 0u;
    UARTMTH2    = 0u;
}
/* EOF */
